<template>
    <div id="container"></div>
</template>
<script setup lang="ts">
import { reactive, onMounted } from 'vue';
import * as THREE from "three"
import { OrbitControls } from "three/examples/jsm/Addons.js"
import globalGeoJson from "@/assets/geojson/countries.json"
import * as d3 from "d3"

const projection = d3
    .geoMercator()
    .center([104.0, 37.5])
    .scale(80)
    .translate([0, 0])

const data = reactive({

})
let scene: THREE.Scene
const init3D = (canvasDOM: HTMLDivElement) => {
    scene = new THREE.Scene()
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
    camera.position.set(-10, 20, -20)
    scene.add(camera)

    const earthGeometry = new THREE.SphereGeometry(5, 30, 30)
    const earthMaterial = new THREE.MeshBasicMaterial({
        color: 0x4466ff,
        // wireframe:true
        transparent: true,
        opacity: 0.5,
    })
    const earthMesh = new THREE.Mesh(earthGeometry, earthMaterial)
    scene.add(earthMesh)

    createMap()

    const renderer = new THREE.WebGLRenderer()
    renderer.setSize(window.innerWidth, window.innerHeight)
    canvasDOM.appendChild(renderer.domElement)

    const axesHelper = new THREE.AxesHelper(500);
    scene.add(axesHelper);
    const controls = new OrbitControls(camera, canvasDOM)
    const animation = () => {
        renderer.render(scene, camera)
        requestAnimationFrame(animation)
    }
    animation()
}
const createMap = () => {
    const map = new THREE.Group()
    // @ts-ignore
    globalGeoJson.features.forEach((feature: any) => {
        let coordinates
        if (feature.geometry.type === "MultiPolygon") {
            coordinates = feature.geometry.coordinates
        } else {
            coordinates = [feature.geometry.coordinates]
        }
        coordinates.forEach((polygon: any) => {
            map.add(
                new THREE.Mesh(
                    createPolygo(polygon, 6).geo,
                    new THREE.MeshBasicMaterial({color:0xffffff,side:THREE.DoubleSide})
                )
            )
        })
    })
    scene.add(map)
}
const createPolygo = (Polygon: any, radius: number) => {
    let vertices: THREE.Vector3[] = []
    let points: [number, number][] = []
    Polygon.forEach((area: [number, number][]) => {
        area = area.slice(0,10)
        area.forEach((coordnates: [number, number]) => {
            vertices.push(new THREE.Vector3().setFromSpherical(new THREE.Spherical(radius, Math.PI / 2 - coordnates[1] / 180 * Math.PI, coordnates[0] / 180 * Math.PI)))
            points.push(projection(coordnates) as [number, number])
        })
    })
    const shape = new THREE.Shape()
    points.forEach((i, index) => {
        if (index) {
            shape.lineTo(i[0], i[1])
        } else {
            shape.moveTo(i[0], i[1])
        }
    })
    const threeDgeo = new THREE.ShapeGeometry(shape)
    const invert = projection.invert as (point: [number, number]) => [number, number]
    for (let i = 0; i < threeDgeo.attributes.position.count; i++) {
        const lalo = invert([threeDgeo.attributes.position.array[i * 3], threeDgeo.attributes.position.array[i * 3 + 1]])
        let np = new THREE.Vector3().setFromSpherical(new THREE.Spherical(radius, Math.PI / 2 - lalo[1] / 180 * Math.PI, lalo[0] / 180 * Math.PI))
        threeDgeo.attributes.position.array[i * 3] = np.x
        threeDgeo.attributes.position.array[i * 3 + 1] = np.y
        threeDgeo.attributes.position.array[i * 3 + 2] = np.z
    }
    return { geo: new THREE.BufferGeometry().setFromPoints(vertices), threeDgeo }
}

onMounted(() => {
    const canvasDOM: HTMLDivElement = document.getElementById("container")!
    init3D(canvasDOM)
})
</script>